/*===========================================================
 
 .---=||||[ B L O O D Y ]|||||=====================----------....
 |                                                              |
 |    THE  M O S T   B L O O D Y  GAME EVER!                    |
 |                                                              |
 |    bloody harvest is coming... soon,                         |
 |                                              heil Satan!     |
 !                                                              !
 .                                                              ,
  ~~~~-------------================================|||||||||==-~




 Name-Space: {core, logic, editor}
 Module: {draw, coll, scgr, ...}
 Class: <name of class>
 Last modification:  <author>, <time>

 TODO:
 <-------- todo #1 ---------->
 <-------- todo #2 ---------->
 <-------- todo #3 ---------->
        ............
 <-------- todo #n ---------->

 FIX:
 <-------- fix #1 ----------->
 <-------- fix #1 ----------->
         ..........
 <-------- fix #n ----------->




 
 
 ============================================================*/
#include <GL/glew.h>
#include "core/draw/IndexBuffer.h"
#include "core/exceptions.h"

namespace core
{
	namespace draw
	{


		IndexBuffer::IndexBuffer(u32 size, GLenum usage)
		{
			std::cout << "-I-B-" << std::endl;
			this->usingVbo = GLEW_ARB_vertex_buffer_object;
			this->vboUsage = usage;
			this->size = size;


			if (this->usingVbo){
				this->data = 0;
				glGenBuffersARB(1, &this->vboId);
				glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, vboId);
				glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, size * sizeof(u32), 0, vboUsage);
			}
			else{
				this->data = new u32[size];
			}


			this->locked = false;
		}

		IndexBuffer::~IndexBuffer()
		{
			if (usingVbo){
				glDeleteBuffersARB(1, &this->vboId);
			}
			else{
				delete [] this->data;
			}
		}

		u32* IndexBuffer::lock(GLenum access)
		{
			this->vboAccess = access;

			if (locked){
				throw InvalidOperationException("IndexBuffer: Locking locked index buffer");
			}

			u32* ret = data;
			if (this->usingVbo){
				glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, vboId);
				ret = (u32*)glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER, access);
			}
	
			locked = true;
			return ret;
		}

		void IndexBuffer::unlock()
		{
			if (!locked){
				throw InvalidOperationException("IndexBuffer: Unlocking unlocked index buffer");
			}

			if (usingVbo){
				glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER);
			}

			locked = false;
		}

		void IndexBuffer::bind()
		{
			glEnable(GL_INDEX_ARRAY);
			if (usingVbo){
				glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, vboId);
			}
			glIndexPointer(GL_INT, sizeof(u32), data);
		}

		void IndexBuffer::unbind()
		{
			glDisable(GL_INDEX_ARRAY);
		}

		void IndexBuffer::draw(VertexBuffer* vb, GLenum primitiveType, int off, int count)
		{
			vb->bind();
			bind();
			glDrawElements(primitiveType, count, GL_UNSIGNED_INT, &data[off]);
			unbind();
			vb->unbind();
		}

	}
}
